package no.rmz.chez.tournament;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import no.rmz.chez.chess.board.Color;
import no.rmz.chez.evaluators.FancyEvaluator;
import no.rmz.chez.game.Game;
import no.rmz.chez.game.reporters.GameReporter;
import no.rmz.chez.game.reporters.StdoutGameReporter;
import no.rmz.chez.players.ChessPlayer;
import no.rmz.chez.players.MinimaxPlayer;

/**
 * Implement an abstract tournament where ChessPlayers are matched
 * against each other, and where the results of the matches
 * is translated into ranking for the ChessPlayers.
 *
 */
public class Tournament implements Runnable {

    /**
     * Create a new tournament without any
     * players.
     *
     */
	public Tournament() {
   
        this ((Set<ChessPlayer>)Collections.EMPTY_SET);
    }

    /**
     * Create a new tournament where the initial players
     * is collected from an existing set of players.
     * @param p
     */
    public Tournament(Set<ChessPlayer> p) {
        this.players = new HashSet<>(p);
    }

    /**
     * All the players participating in the tournament.
     */
    private Collection<ChessPlayer> players;

    /**
     * The game reporter used by the tournament.
     */
   // private GameReporter gr = new QuietReporter();
     private GameReporter gr = new StdoutGameReporter();

    /**
     * Create then return a new game suitable for use in a tournament.
     * 
     * @param white the white player.
     * @param black the black player.
     * @return a game usable in a tournament.
     */
    public Game newTournamentGame(
            final ChessPlayer white,
            final ChessPlayer black){
        return new Game(white, black, gr);
    }

    /**
     * Collecting the result from this tournament.
     */
    private final TournamentResult result = new TournamentResult();

    /**
     * Getting the results.
     */
    
    public final TournamentResult getResult() {
        return result;
    }
    
    /**
     * Run the tournament.
     */
    @Override
    public final void run() {
        final List<ChessPlayer> ps = new LinkedList<>(players);
        final int            np = ps.size();

        // Traverse the upper triangular matrice of
        // possible pairs of ChessPlayers, then match them
        // through two games.

        for (int i = 0; i < np; i++) {
            for (int j =  i + 1; j < np; j++) {
                final ChessPlayer pa = ps.get(i);
                final ChessPlayer pb = ps.get(j);
                
                System.out.println("Tournament matching " + pa + " against " + pb);

                // Set up  & run games!
                pa.setColor(Color.BLACK);
                pb.setColor(Color.WHITE);
                final Game g1 = newTournamentGame(pa, pb);
                g1.run();
                System.out.println("First game " + g1);
                result.addGameResult(pa, pb, g1);

                pa.setColor(Color.WHITE);
                pb.setColor(Color.BLACK);
                final Game g2 = newTournamentGame(pa, pb);
                g2.run();
                System.out.println("Second game " + g2);
                result.addGameResult(pb, pa, g2);
            }
        }
    }
    
    /**
     * Smoketest for playing a tournament.
     * @param argv
     */
    public static void main(final String [] argv) {
        
        // Generate a set of players
        final int minimumLookahead = 2;
        final int maximumLookahead = 5;
        final Set<ChessPlayer> players = new HashSet<>();
        for (int lookahead = minimumLookahead ; 
                 lookahead <= maximumLookahead; 
                 lookahead++) {
            final ChessPlayer p =
                new MinimaxPlayer(lookahead, FancyEvaluator.getInstance());
            players.add(p);
        }
        
        // Run the tournament
        final Tournament t = new Tournament(players);
        t.run();
        
        // Print the results
        System.out.println(t.getResult());
    }
}
